package com.DJRelayAndroidClient_ACE.djrelay_androidclient;


import java.lang.ref.WeakReference;

import org.json.JSONException;
import org.json.JSONObject;

import com.DJRelayAndroidClient_ACE.djrelay_androidclient.LoginActivity.ServerHandler;
import com.google.android.youtube.player.YouTubePlayer;
import com.google.android.youtube.player.YouTubePlayer.ErrorReason;
import com.google.android.youtube.player.YouTubePlayer.PlayerStateChangeListener;
import com.google.android.youtube.player.YouTubePlayerView;
import com.google.android.youtube.player.YouTubePlayer.Provider;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.Toast;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.TextView;
import android.widget.ToggleButton;

public class MainActivity extends YouTubeFailureRecoveryActivity {

	/* ***Global constants*** */
	public static final int MAIN_ACTIVITY = 1;
	public static final int LOGIN_ACTIVITY = 2;
//	public static final String serverAddress = "http://192.168.1.76/relayView.php";	// pi host
//	public String songCueAddress = "http://192.168.1.76/selected_tubeID.txt";
//	public static final String serverAddress = "http://173.229.0.209/relayView.php";	// djRelayDev host
//	public static final String songCueAddress = "http://173.229.0.209/selected_tubeID.txt";
	public static final String serverAddress = "http://192.168.1.71/DJ_Relay_Server/relayMain.php";	// local xampp host
	public static final String songCueAddress = "http://192.168.1.71/DJ_Relay_Server/selected_tubeID.txt";
	
	public enum requestType {CREATE_SESSION, JOIN_SESSION, UPDATE_SONG, UPDATE_FEED,	// Client request types to server
							 FETCH_FEED, USER_LOG_OUT, KILL_SESSION};	
							 
	// Server Status Fields
	public static String dbCon = "false", createTable = "false", insertMaster = "false", insertUser = "false", 
				   updateUser = "false", masterPresent = "false", usersPresent = "false",updateFeed = "false", 
				   sessionKill = "false";
	public static JSONObject selectedUser;
	/* *************************************************************/
	
	public static Handler mHandler;
	public static ServerHandler mServerHandler;
	private static HttpHelper mHttpHelper;
	
	private static final int REQUEST_CODE_YOUTUBE_SEARCH = 0;
	private static final int REQUEST_CODE_LOGIN = 1;
	
    private Button song_submit, search_song, sign_out;
    private ToggleButton feed_select;
    private TextView mTextView2;
	
	private static String mSong = "No Song Selected..";
	private static String mSongID = "wKJ9KzGQq0w";
	private String feedSongID;
	
	private static String mUserName;
	private static String mUserID;
	private static String mSessionID;
	
	private static String randSong = null;	// TODO - still need implementation for feed info
	private static String randSongID = null;
	
	private static YouTubePlayer mPlayer = null;
	
	private boolean tubeAdStarted = false;	// Tube Monitoring flags
	private boolean tubeLoaded = false;
	private boolean tubeLoading = false;
	private boolean tubeVidEnd = false;
	private boolean tubeVidStart = false;
	
	private static boolean userSignedIn = false;
	
	@Override 
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        song_submit = (Button) findViewById(R.id.song_select_button);
        song_submit.setOnClickListener(mSongSubmit);

        search_song = (Button) findViewById(R.id.search);
        search_song.setOnClickListener(mBrowser);	
        
        sign_out = (Button) findViewById(R.id.mainSignOut_button);
        sign_out.setOnClickListener(mLogin);
        
        feed_select = (ToggleButton) findViewById(R.id.tubeFeed_toggleButton);
        feed_select.setOnCheckedChangeListener(mFeedSelect);
        
        mTextView2 = (TextView) findViewById(R.id.firstName_textView);
        mTextView2.setText(mSong);
        
        mHttpHelper = new HttpHelper(MAIN_ACTIVITY);
        
		mServerHandler = new ServerHandler(this);
        
        YouTubePlayerView youTubeView = (YouTubePlayerView) findViewById(R.id.youtube_player);
        youTubeView.initialize(DeveloperKey.DEVELOPER_KEY, this);
       
        // TODO - fix this hack so that back button press on LoginActivity doesn't bring us back to MainActivity
        // TODO - May have to make the LoginActivity the entry point for the application..
    	if (!userSignedIn){
        	Intent login = new Intent(getBaseContext(), LoginActivity.class);
        	startActivityForResult(login, REQUEST_CODE_LOGIN);
    	}
	}
	
	static class ServerHandler extends Handler {
		private final WeakReference<MainActivity> mMainActivity;
		
		ServerHandler(MainActivity mainActivity) {
			mMainActivity = new WeakReference<MainActivity>(mainActivity);
		}

    	@Override
    	public void handleMessage(Message msg){
    		MainActivity mainActivity = mMainActivity.get();
    		if (mainActivity != null) {
    			mainActivity.handleMessage(msg);
    		}
    	}
	}
	
	public void handleMessage(Message msg){
		/* *** Return codes: ***
		 0 = HTTP error
		 1 = JSON error
		 2 = CREATE_TABLE success
		 3 = JOIN_TABLE success
		 4 = UPDATE_SONG success
		 5 = UPDATE_FEED success
		 6 = FETCH_FEED success
		 7 = USER_LOG_OUT success
		 8 = KILL_SESSION success
		 ************************** */
		Log.d("myApp", "Message Handler invoked");
		if (msg.what == 0)		// This still takes too long to realize server connection is down..
			popServerError();
		
		else if (msg.what == 1) {
			// TODO - user notification??
			Log.w("myApp", "Handler message not received properly, JSON error in HTTP Helper");       			
		}
		
		else if(msg.what == 4) {
			readServerResponse(requestType.UPDATE_SONG, mHttpHelper);
			if (dbCon == "true" && updateUser == "true") {
				Log.i("myApp", "User song update success");
				// TODO - pop update success dialog??
			} else {
				Log.w("myApp", "User song update failure, dbCon = " + dbCon
						+ "updateUser = " + updateUser);
				// TODO - notify user, specify details of database connection issue
				// e.g. existing user, master, etc..
			}
		}
		
		else if(msg.what == 5){
			readServerResponse(requestType.UPDATE_FEED, mHttpHelper);
			if (dbCon == "true" && masterPresent == "true" && usersPresent == "true"
					&& updateFeed  == "true"){
				Log.i("myApp", "Feed update success");
   			try {
   				randSongID = selectedUser.getString("selected_tubeID");
   				mPlayer.cueVideo(randSongID);			// TODO - Ideally this plays automatically..
   			} catch (NullPointerException npe) {
   				Log.w("myApp", "Either HTTP class or Tube Player Not instantiated!!" + npe.toString());
   			} catch (JSONException je) {
					Log.w("myApp", "JSON Object Exception: " + je.getMessage());
				}
			} else {
				Log.w("myApp", "User song update failure, dbCon = " + dbCon
						+ "masterPresent = " + masterPresent + ", usersPresent = " + usersPresent + 
						", updateFeed = " + updateFeed);
				// TODO - notify user, specify details of database connection issue
				// e.g. existing user, master, etc..
			}

		}
		
		else if(msg.what == 6) {
			readServerResponse(requestType.FETCH_FEED, mHttpHelper);
			if (dbCon == "true" && masterPresent == "true") {
				Log.i("myApp", "Current Feed retrieval success");
				// TODO - pop update success dialog??
				try {
					feedSongID = selectedUser.getString("selected_tubeID");
					mPlayer.cueVideo(feedSongID);
				} catch (JSONException je) {
					Log.w("myApp", "JSON Object Exception: " + je.getMessage());
				}
			} else {
				Log.w("myApp", "User song update failure, dbCon = " + dbCon
						+ "masterPresent = " + masterPresent);
				// TODO - notify user, specify details of database connection issue
				// e.g. existing user, master, etc..
			}
		}
		
		else if(msg.what == 7) {
			readServerResponse(requestType.USER_LOG_OUT, mHttpHelper);
			if (dbCon == "true" && updateUser == "true") {
				Log.i("myApp", "User log out success");
				userLogOut();
			} else {
				Log.w("myApp", "User song update failure, dbCon = " + dbCon
						+ "updateUser = " + updateUser);
				// TODO - notify user, specify details of database connection issue
				// e.g. existing user, master, etc..
			}
		}
		
		else if(msg.what == 8) {
			readServerResponse(requestType.KILL_SESSION, mHttpHelper);
			if (dbCon == "true" && masterPresent == "true" && sessionKill == "true") {
				Log.i("myApp", "Kill session success");
				userLogOut();
			} else {
				Log.w("myApp", "Kill session failure, dbCon = " + dbCon
						+ ", masterPresent = " + masterPresent + ", sessionKill = " + sessionKill);
				// TODO - notify user, specify details of database connection issue
				// e.g. existing user, master, etc..
			} 
		}
		else {
			Log.w("myApp", "HttpHelper didn't return an expected return ID");
		}
	}
	
	private PlayerStateChangeListener mTubeListener = new PlayerStateChangeListener() {

		@Override
		public void onAdStarted() {
			tubeAdStarted = true;
			tubeLoaded = false;
			tubeLoading = false;
			tubeVidEnd = false;
			tubeVidStart = false;
			Log.i("myApp", "onAdStarted() = " + tubeAdStarted);
		}

		@Override
		public void onError(ErrorReason arg0) {
			// TODO Auto-generated method stub
			
			tubeAdStarted = false;
			tubeLoaded = false;
			tubeLoading = false;
			tubeVidEnd = false;
			tubeVidStart = false;
			Log.i("myApp", "onError() -> YouTube Error.. " + arg0.toString());
		}

		@Override
		public void onLoaded(String arg0) {
			tubeAdStarted = false;
			tubeLoaded = true;
			tubeLoading = false;
			tubeVidEnd = false;
			tubeVidStart = false;
			Log.i("myApp", "onLoaded() = " + tubeLoaded);
		}

		@Override
		public void onLoading() {
			tubeAdStarted = false;
			tubeLoaded = false;
			tubeLoading = true;
			tubeVidEnd = false;
			tubeVidStart = false;
			Log.i("myApp", "onLoading() = " + tubeLoading);
		}

		@Override
		public void onVideoEnded() {
			tubeAdStarted = false;
			tubeLoaded = false;
			tubeLoading = false;
			tubeVidEnd = true;
			tubeVidStart = false;	
			Log.i("myApp", "onVideoEnded() = " + tubeVidEnd);
        	try {
        		// TODO - need to make this conditional on whether user is the master or not!
        		// TODO - this doesn't feel fail proof, but will do for now..
        		if (LoginActivity.createSession && feed_select.isChecked())
        			mHttpHelper.httpPostGet(requestType.FETCH_FEED, serverAddress, 
							songCueAddress, "updateFeed", "true",
							"sessionID", mSessionID,
							"user", mUserName,
							"userID", mUserID);
        	} catch (NullPointerException npe) {
        		Log.w("myApp", "No HTTP Helper Class Instantiated!");
        		// TODO - maybe add some useful notification??
        	}
		}

		@Override
		public void onVideoStarted() {
			tubeAdStarted = false;
			tubeLoaded = false;
			tubeLoading = false;
			tubeVidEnd = false;
			tubeVidStart = true;
			Log.i("myApp", "onVideoStarted() = " + tubeVidStart);
		}
	};
	
	private OnClickListener mBrowser = new OnClickListener() {
        public void onClick(View button) {
        	Intent youTubeSearch = new Intent(getBaseContext(), SearchActivity.class);
        	startActivityForResult(youTubeSearch, REQUEST_CODE_YOUTUBE_SEARCH);
        }
	};
	
	private OnClickListener mLogin = new OnClickListener() {
        public void onClick(View button) {
        	if (LoginActivity.createSession) {
    			mHttpHelper.httpPostGet(requestType.KILL_SESSION, serverAddress, 
						songCueAddress, "killSession", "true",
						"sessionID", mSessionID,
						"user", mUserName,
						"userID", mUserID);
        	} else {
    			mHttpHelper.httpPostGet(requestType.USER_LOG_OUT, serverAddress, 
						songCueAddress, "userLogOut", "true",
						"sessionID", mSessionID,
						"user", mUserName,
						"userID", mUserID);       		
        	}
        		
        }
	};
	
	
	public synchronized void onActivityResult(final int requestCode, int resultCode, final Intent data){
		if (requestCode == REQUEST_CODE_YOUTUBE_SEARCH) {
			if (resultCode == Activity.RESULT_OK) {
				Bundle extras = data.getExtras();
				if (extras != null){
					mSong = extras.getString("SONG_TITLE");
					mSongID = extras.getString("SONG_ID");
					Log.i("myApp", mSong);
					Log.i("myApp", mSongID);

					try {
						mTextView2.setText(mSong);
						mPlayer.cueVideo(mSongID);
						// while (!tubeLoaded){}		// Something like this would be nice, but
						// mPlayer.loadVideo(mSongID);	// this doesn't work ...
						mPlayer.play();
					}
					catch (NullPointerException npe){
						Log.e("myApp", "No instance of YouTube Player!!");
						return;
					}
				} 
				else
					Log.e("myApp", "YouTube Search extras object not received!");
			} 
			else if (resultCode == Activity.RESULT_CANCELED) {
				// TODO - cancellation handling?
			}
		}
		if (requestCode == REQUEST_CODE_LOGIN) {
			Log.d("myApp", "Login Request code received");
			if (resultCode == Activity.RESULT_OK) {
				Bundle extras = data.getExtras();
				if (extras != null){
					Log.d("myApp", "extras received from login activity");
					mUserName = extras.getString("NAME");
					mUserID = extras.getString("ID");
					mSessionID = extras.getString("SESSION_ID");
					userSignedIn = true;		
					Log.i("myApp", mUserName);
					Log.i("myApp", mUserID);
				} 
				else
					Log.e("myApp", "Login extras object not received!");
			} 
			else if (resultCode == Activity.RESULT_CANCELED) {
				// TODO - cancellation handling?
			}
		}
	}
	
	  @Override
	  public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer player,
	      boolean wasRestored) {
		  mPlayer = player;
		  mPlayer.setPlayerStateChangeListener(mTubeListener);
		  // Need something like this to switch to fullscreen mode on landscape change
		  // However, it is crashing horrifically @ the moment and I don't want to deal w/ this shit right now
//		  mPlayer.setFullscreenControlFlags(YouTubePlayer.FULLSCREEN_FLAG_CONTROL_ORIENTATION | 
//				  							YouTubePlayer.FULLSCREEN_FLAG_ALWAYS_FULLSCREEN_IN_LANDSCAPE);
		  Log.i("myApp", "Entering YouTube Initialization callback");
		  if (!wasRestored)
			  mPlayer.cueVideo("wKJ9KzGQq0w");
	  }



	@Override
	protected Provider getYouTubePlayerProvider() {
		return (YouTubePlayerView) findViewById(R.id.youtube_player);
	}

	
    private OnClickListener mSongSubmit = new OnClickListener() {
        public void onClick(View button) {
        	try {
        		mHttpHelper.httpPostGet(requestType.UPDATE_SONG, serverAddress, 
        								songCueAddress, "updateSong", "true", 
        								"selected_tubeID", mSongID, 
    									"sessionID", mSessionID,
    									"user", mUserName,
    									"userID", mUserID);
        	} catch (NullPointerException npe) {
        		Log.w("myApp", "No HTTP Helper Class Instantiated!");
        		// TODO - maybe add some useful notification??
        	}
        }
    };  
    
    
	private OnCheckedChangeListener mFeedSelect = new OnCheckedChangeListener() {
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        	if (isChecked){
        		try {
        			Log.i("myApp", "Feed Select Params: Session ID = " + mSessionID + 
        					" user = " + mUserName + " userID = " + mUserID);
        			mHttpHelper.httpPostGet(requestType.FETCH_FEED, serverAddress, 
        									songCueAddress, "fetchFeed", "true",
        									"sessionID", mSessionID,
        									"user", mUserName,
        									"userID", mUserID);
        			// TODO - maybe add a progress dialog??
        		} catch (Exception e) {
        			Log.w("myApp", "Toggle button Exception: " + e.toString());
        		}
        	} else {
        		try {
        			mPlayer.cueVideo(mSongID);
        		} catch (Exception e) {
        			Log.w("myApp", "Error toggling back to user selected song: " + e.toString());
        		}
        	}
        }
	};
    
	public static void readServerResponse(requestType request, HttpHelper HttpHelper) {
		switch(request) {
		case CREATE_SESSION:
			try {
				// TODO - may need to create input for values to read,
				// otherwise exception is thrown when value doesn't exist and we don't get rest of values..

				// Collect Status bits from Server query and check for any errors
				dbCon         =  HttpHelper.jsonData.getString("dbCon");
				createTable   =  HttpHelper.jsonData.getString("createTable");
				insertMaster  =  HttpHelper.jsonData.getString("insertMaster");

			} catch (JSONException je) {
				Log.w("myApp", "JSONObject for CREATE_SESSION not returned: " + je.getMessage());
				// TODO notify user
			} catch (Exception e) {
				Log.d("myApp", "Exception caught in CREATE_SESSION JSON Object: " + e.getMessage());
				// TODO to be determined..
			}
			break;
		case JOIN_SESSION:
			try {
				// TODO - may need to create input for values to read,
				// otherwise exception is thrown when value doesn't exist and we don't get rest of values..

				// Collect Status bits from Server query and check for any errors
				dbCon         =  HttpHelper.jsonData.getString("dbCon");
				insertUser    =  HttpHelper.jsonData.getString("insertUser");

			} catch (JSONException je) {
				Log.w("myApp", "JSONObject for JOIN_SESSION not returned: " + je.getMessage());
				// TODO notify user
			} catch (Exception e) {
				Log.d("myApp", "Exception caught in JOIN_SESSION JSON Object: " + e.getMessage());
				// TODO to be determined..
			}
			break;
		case UPDATE_SONG:
			try {
				// TODO - may need to create input for values to read,
				// otherwise exception is thrown when value doesn't exist and we don't get rest of values..

				// Collect Status bits from Server query and check for any errors
				dbCon         =  HttpHelper.jsonData.getString("dbCon");
				updateUser    =  HttpHelper.jsonData.getString("updateUser");

			} catch (JSONException je) {
				Log.w("myApp", "JSONObject for UDPATE_SONG not returned: " + je.getMessage());
				// TODO notify user
			} catch (Exception e) {
				Log.d("myApp", "Exception caught in UDPATE_SONG JSON Object: " + e.getMessage());
				// TODO to be determined..
			}
			break;
		case UPDATE_FEED:
			try {
				// TODO - may need to create input for values to read,
				// otherwise exception is thrown when value doesn't exist and we don't get rest of values..

				// Collect Status bits from Server query and check for any errors
				dbCon         =  HttpHelper.jsonData.getString("dbCon");
				masterPresent =  HttpHelper.jsonData.getString("masterPresent");
				usersPresent  =  HttpHelper.jsonData.getString("usersPresent");
				updateFeed    =  HttpHelper.jsonData.getString("updateFeed");			
				selectedUser  =  HttpHelper.jsonData.getJSONObject("selectedUser");

			} catch (JSONException je) {
				Log.w("myApp", "JSONObject for UDPATE_FEED not returned: " + je.getMessage());
				// TODO notify user
			} catch (Exception e) {
				Log.d("myApp", "Exception caught in UPDATE_FEED JSON Object: " + e.getMessage());
				// TODO to be determined..
			}
			break;
		case FETCH_FEED:
			try {
				// TODO - may need to create input for values to read,
				// otherwise exception is thrown when value doesn't exist and we don't get rest of values..

				// Collect Status bits from Server query and check for any errors
				dbCon         =  HttpHelper.jsonData.getString("dbCon");
				masterPresent =  HttpHelper.jsonData.getString("masterPresent");
				selectedUser  =  HttpHelper.jsonData.getJSONObject("selectedUser");

			} catch (JSONException je) {
				Log.w("myApp", "JSONObject for FETCH_FEED not returned: " + je.getMessage());
				// TODO notify user
			} catch (Exception e) {
				Log.d("myApp", "Exception caught in FETCH_FEED JSON Object: " + e.getMessage());
				// TODO to be determined..
			}
			break;		
		case USER_LOG_OUT:
			try {
				// TODO - may need to create input for values to read,
				// otherwise exception is thrown when value doesn't exist and we don't get rest of values..

				// Collect Status bits from Server query and check for any errors
				dbCon         =  HttpHelper.jsonData.getString("dbCon");
				updateUser    =  HttpHelper.jsonData.getString("updateUser");

			} catch (JSONException je) {
				Log.w("myApp", "JSONObject for USER_LOG_OUT not returned: " + je.getMessage());
				// TODO notify user
			} catch (Exception e) {
				Log.d("myApp", "Exception caught in USER_LOG_OUT JSON Object: " + e.getMessage());
				// TODO to be determined..
			}
			break;		
		case KILL_SESSION:
			try {
				// TODO - may need to create input for values to read,
				// otherwise exception is thrown when value doesn't exist and we don't get rest of values..

				// Collect Status bits from Server query and check for any errors
				dbCon         =  HttpHelper.jsonData.getString("dbCon");
				masterPresent =  HttpHelper.jsonData.getString("masterPresent");			
				sessionKill   =  HttpHelper.jsonData.getString("sessionKill");

			} catch (JSONException je) {
				Log.w("myApp", "JSONObject for KILL_SESSION not returned: " + je.getMessage());
				// TODO notify user
			} catch (Exception e) {
				Log.d("myApp", "Exception caught in KILL_SESSION JSON Object: " + e.getMessage());
				// TODO to be determined..
			}
			break;
		}
	}
	
	private void popServerError() {
		Context context = getApplicationContext();
		CharSequence text = "DJ Relay servers are down. Try again later..";
		int duration = Toast.LENGTH_SHORT;

		Toast toast = Toast.makeText(context, text, duration);
		toast.setGravity(Gravity.CENTER | Gravity.CENTER, 0, 0);
		toast.show();
	}
	
	private void userLogOut() {
		Intent login = new Intent(getBaseContext(), LoginActivity.class);
		Bundle b = new Bundle();
		b.putInt("SignOut", 1);
		login.putExtras(b);
		userSignedIn = false;
		startActivityForResult(login, REQUEST_CODE_LOGIN);
	}
    
    
    @Override
    public void onStart() {
        super.onStart();        
    }

    @Override
    public synchronized void onResume() {
        super.onResume();
    }
    
    @Override
    public synchronized void onPause() {
        super.onPause();
    }

    @Override
    public void onStop() {
        super.onStop();
    }

    @Override
    public void onDestroy() {
    	super.onDestroy();
    }    
}
